package com.ruoyi.accounts.tcp;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.accounts.mapper.EmpPropertyMapper;
import lombok.SneakyThrows;
import lombok.var;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.websocket.Session;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.*;


/*
游戏状态
*/
@Service
public class GameStateService {
    private static final Logger log = LoggerFactory.getLogger(GameStateService.class);

    /// 机器占用信息
    public static Map<String, String> OCCUPYMACHINE = new ConcurrentHashMap<>();
    private static Map<String, LocalDateTime> OCCUPYTIME = new ConcurrentHashMap<>();
    private static Map<String, GameStateEnum> GAMESTATE = new ConcurrentHashMap<>();

    @Autowired
    EmpPropertyMapper empPropertyMapper;

    private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

    // 定时下抓任务
    private static Map<String, ScheduledFuture<?>> AUTOPLAY = new ConcurrentHashMap<>();

    public static ScheduledFuture<?> scheduleTask(String user, Runnable task, long delay) {
        var t = scheduler.schedule(task, delay, TimeUnit.SECONDS);
        AUTOPLAY.put(user, t);
        return t;
    }

    public static void cancelTask(String user) {
        var task = AUTOPLAY.get(user);

        if (task != null && !task.isDone()) {
            task.cancel(false);
        }

        AUTOPLAY.remove(user);
    }

    /// 尝试占机
    /// 断线后判断
    public static boolean tryTakeUp(String user, String uid) {
        // 用户没有占用记录，且没其他人占用机器
        if (!OCCUPYMACHINE.containsKey(user) && !OCCUPYMACHINE.containsValue(uid)) {
            OCCUPYMACHINE.put(user, uid);
            OCCUPYTIME.put(user, LocalDateTime.now());
            return true;
        }
        // 用户有占用记录，且占用的是同一个机器
        else if (OCCUPYMACHINE.containsKey(user) && OCCUPYMACHINE.get(user).equals(uid)) {
            OCCUPYTIME.remove(user);
            OCCUPYTIME.put(user, LocalDateTime.now());
            return true;
        } else
            return false;
    }

    // 用户是否占用了该机器
    public static boolean isTakeUp(String user, String uid) {
        return OCCUPYMACHINE.containsKey(user) && OCCUPYMACHINE.get(user).equals(uid);
    }

    /// 更新占机状态，不更新则在达到最大占机时间后释放机器
    public static void refresh(String user) {
        if (OCCUPYTIME.containsKey(user)) {
            OCCUPYTIME.remove(user);
            OCCUPYTIME.put(user, LocalDateTime.now());
        }
    }

    /// 打印占机时间参数
    public static void refreshPrint(String user) {
        if (OCCUPYTIME.containsKey(user)) {
            var value = OCCUPYTIME.get(user);
            log.info("当前记录占机时间：" + value.toString());
            log.info("当前时间：" + LocalDateTime.now().toString());
        } else {
            log.info("没有" + user + "占机信息");
        }
    }

    public static void setGameState(String user, GameStateEnum gameState) {
        GAMESTATE.remove(user);
        GAMESTATE.put(user, gameState);
    }

    public static GameStateEnum getGameState(String user) {
        if (GAMESTATE.containsKey(user)) {
            return GAMESTATE.get(user);
        }
        return null;
    }
    
    public static void removeGameState(String user) {
        GAMESTATE.remove(user);
    }

    /// 每秒检查有没有超时的占机信息
    @Scheduled(cron = "0/3 * * * * ?")
    public void checkOccupy() {
        Iterator<Map.Entry<String, LocalDateTime>> iterator = OCCUPYTIME.entrySet().iterator();
        var flag = false;
        while (iterator.hasNext()) {
            Map.Entry<String, LocalDateTime> entry = iterator.next();
            LocalDateTime value = entry.getValue();
            LocalDateTime now = LocalDateTime.now();
            //System.out.println("检查占用 " + entry.getKey() + "  " + value + " " + Duration.between(now, value).getSeconds());

            var mid = OCCUPYMACHINE.get(entry.getKey());
            var occupyTime = 30;
            var machine = empPropertyMapper.getByEquipmentID(mid);
            if (machine != null && machine.getOccupyTime() != null) {
                occupyTime = machine.getOccupyTime();
            }

            if (Duration.between(value, now).getSeconds() > occupyTime) {
                GAMESTATE.remove(entry.getKey());
                OCCUPYMACHINE.remove(entry.getKey());
                OCCUPYTIME.remove(entry.getKey());
                iterator.remove();
                System.out.println("移除占用 " + entry.getKey() + "  " + value);
                flag = true;
            }
        }
        if (flag) {
            sendLiveTask();
        }
    }

    // 广播消息
    @Scheduled(cron = "0/10 * * * * ?")
    public void sendLiveTask() {
        for (var entry : WebSocketService.SESSIONS.entrySet()) {
            var session = entry.getValue();
            if (session != null) {
                // 占机的信息
                sendLiveData(session, "take", GameStateService.OCCUPYMACHINE.values());
                System.out.println("[Websocket Send ]: " + " take " + GameStateService.OCCUPYMACHINE.values());
            }
        }
    }

    public static void boardcast(String msg) {
        for (var entry : WebSocketService.SESSIONS.entrySet()) {
            var session = entry.getValue();
            if (session != null) {
                sendLiveData(session, "roll", msg);
                System.out.println("[Websocket Send ]: " + " roll " + msg);
            }
        }
    }

    @SneakyThrows
    public static void sendLiveData(String user, String msg, Object data) {
        var resp = new WSRespone(true, msg, data);
        ObjectMapper ob = new ObjectMapper();
        var session = WebSocketService.SESSIONS.get(user);
        if (session != null) {
            session.getBasicRemote().sendText(ob.writeValueAsString(resp));
            System.out.println("[Websocket Send ]: " + ob.writeValueAsString(resp));
        }
    }

    @SneakyThrows
    public static void sendLiveData(Session session, String msg, Object data) {
        var resp = new WSRespone(true, msg, data);
        ObjectMapper ob = new ObjectMapper();
        if (session != null) {
            session.getBasicRemote().sendText(ob.writeValueAsString(resp));
            System.out.println("[Websocket Send ]: " + ob.writeValueAsString(resp));
        }
    }

    @SneakyThrows
    public static void sendLiveData(String user, String msg, Object data, Boolean result) {
        var resp = new WSRespone(result, msg, data);
        ObjectMapper ob = new ObjectMapper();
        var session = WebSocketService.SESSIONS.get(user);
        if (session != null) {
            session.getBasicRemote().sendText(ob.writeValueAsString(resp));
            System.out.println("[Websocket Send ]: " + ob.writeValueAsString(resp));
        }
    }
}
